// eslint-disable-next-line import/named
import { ActionTree } from 'vuex'
import { StateInterface } from '../state'
import { AppWidgetData, Widget, WidgetStateInterface } from './state'
import _ from 'lodash'
import { genWidgetId, getNextWidgetPos } from 'src/utils/widget'

const actions: ActionTree<WidgetStateInterface, StateInterface> = {

  async createWidget ({
    commit,
    dispatch,
    state
  }, widget) {
    const position = getNextWidgetPos(widget.w, widget.h, {
      positions: state.widgets,
      cache: true,
      column: 10
    })
    widget = {
      ...widget,
      ...position
    }
    commit('createWidget', widget)
    dispatch('storeSave', null, { root: true })
  },

  async updateWidget ({
    commit,
    dispatch
  }, widget) {
    commit('updateWidget', widget)
    dispatch('storeSave', null, { root: true })
  },

  async deleteWidget ({
    commit,
    dispatch
  }, widget) {
    commit('deleteWidget', widget)
    dispatch('storeSave', null, { root: true })
  },

  async syncAppWidget ({
    commit,
    state
  }, {
    apps,
    widgets
  }: WidgetStateInterface = state) {
    apps = _.cloneDeep(apps || state.apps)
    widgets = _.cloneDeep(widgets || state.widgets)
    apps && commit('setApps', apps)

    // 根据 Apps 匹配更新 widgets
    // 1. apps 如果删除则 widgets 同步删除 apps
    // 2. apps 如果新增 widgets 不存在的 app，则创建新 widget 装载 app
    // 3. widgets.apps 如果是空数组则删除
    widgets = widgets.map(widget => {
      if (widget.apps) {
        widget.apps = widget.apps.map(app => {
          const matchApp = apps.find((e) => e.id === app.id)
          if (!matchApp) return null
          return {
            ...matchApp,
            ...app
          }
        }).filter(e => e) as AppWidgetData[]
      }
      return widget
    }).filter(e => !e.apps || e.apps.length > 0)

    const deployedApps = _.flatten(widgets.map(e => e.apps).filter(e => e)) as AppWidgetData[]
    const notDeployApps = apps.filter((e: AppWidgetData) => {
      return !deployedApps.find(v => v.id === e.id)
    })
    for (const notDeployApp of notDeployApps) {
      const newWidget: Widget = {
        id: genWidgetId('APP_WIDGET'),
        apps: [notDeployApp],
        ...getNextWidgetPos(2, 1, {
          positions: widgets,
          cache: true,
          column: 10
        }),
        type: 'AppWidget'
      }
      widgets.push(newWidget)
    }

    widgets && commit('setWidgets', widgets)
  },

  async addApp ({
    commit,
    state,
    dispatch
  }, {
    app,
    widgetId
  }) {
    const newApp = {
      id: genWidgetId('APP'),
      type: 2,
      appData: app
    }
    const targetWidget = widgetId && state.widgets.find(e => e.id === widgetId)
    if (targetWidget) {
      commit('setApps', [...state.apps, newApp])
      commit('updateWidget', {
        ...targetWidget,
        apps: [...targetWidget.apps, newApp]
      })
    } else {
      commit('setApps', [...state.apps, newApp])
      dispatch('syncAppWidget')
    }
    dispatch('workbench/emitAppEvent', {
      app: newApp,
      operation: '添加'
    }, { root: true })
    dispatch('storeSave', null, { root: true })
  },

  async updateApp ({
    commit,
    dispatch
  }, app) {
    commit('updateApp', app)
    dispatch('storeSave', null, { root: true })
  },

  async addAppGroup ({
    commit,
    state,
    dispatch
  }, {
    title,
    apps
  }: {
    title: string,
    apps: AppWidgetData[]
  }) {
    const newApps = (apps || []).map(e => {
      return {
        id: genWidgetId('APP'),
        type: 2,
        appData: e
      }
    })
    let size = 'xs'
    let w = 3
    let h = 3
    if (newApps.length <= 6) {
      size = 'md'
      w = 3
      h = 2
    }
    if (newApps.length <= 2) {
      size = 'md'
      w = 2
      h = 2
    }
    const newAppGroupWidget = {
      id: genWidgetId('APP_GROUP_WIDGET'),
      type: 'AppGroupWidget',
      apps: newApps,
      title: title,
      size: size,
      ...getNextWidgetPos(w, h, {
        positions: state.widgets,
        cache: true,
        column: 10
      })
    }
    commit('setApps', [...state.apps, ...newApps])
    commit('createWidget', newAppGroupWidget)
    dispatch('storeSave', null, { root: true })
  },

  async removeCustomApps ({
    commit,
    dispatch
  }, apps) {
    commit('removeMultiApps', apps)
    dispatch('syncAppWidget')
    dispatch('storeSave', null, { root: true })
    for (const app of apps) {
      dispatch('workbench/emitAppEvent', {
        app,
        operation: '删除'
      }, { root: true })
    }
  },

  async removeCollectionApp ({
    commit,
    state,
    dispatch
  }, app) {
    const matchedCollectionApp = state.collectionApps.find(e => e._id === app.appData._id)
    // 删除用户收藏应用
    if (matchedCollectionApp) {
      commit('setCollectionApps', state.collectionApps.filter(e => e._id !== app.appData._id))
      await dispatch('tool/removeToolCollection', app.appData, { root: true })
    }
    // 删除工作台应用
    const matchedApp = state.apps.find(e => e.appData._id === app.appData._id)
    if (matchedApp) {
      commit('setApps', state.apps.filter(e => e.appData._id !== app.appData._id))
    }
    dispatch('syncAppWidget')
  },

  async removeCollectionApps ({ dispatch }, apps) {
    for (const app of apps) {
      await dispatch('removeCollectionApp', app)
    }
  },

  async mergeAppWidget ({
    commit,
    state,
    dispatch
  }, {
    movingWidgetId,
    coveredWidgetId
  }) {
    let coveredWidget = state.widgets.find(e => e.id === coveredWidgetId)
    let movingWidget = state.widgets.find(e => e.id === movingWidgetId)
    coveredWidget = _.cloneDeep(coveredWidget)
    movingWidget = _.cloneDeep(movingWidget)
    if (coveredWidget &&
      movingWidget &&
      coveredWidget.apps &&
      movingWidget.apps) {
      coveredWidget.type = 'AppGroupWidget'
      coveredWidget.title = '应用分组'
      coveredWidget.minH = 2
      coveredWidget.apps = coveredWidget.apps.concat(movingWidget.apps)
      movingWidget.apps = []
      if (coveredWidget.h < 2) {
        coveredWidget.h = 2
        coveredWidget.w = 3
      }
      commit('updateWidget', coveredWidget)
      commit('deleteWidget', movingWidget)
      dispatch('storeSave', null, { root: true })
    } else {
      throw Error('Action mergeAppWidget Fail.')
    }
  },

  async transferAppWidget ({
    commit,
    state,
    dispatch
  }, {
    targetWidgetId,
    appId
  }) {
    const targetWidget = state.widgets.find(e => e.id === targetWidgetId)
    let app: AppWidgetData | undefined
    const fromWidget = state.widgets.find(e => {
      app = (e.apps || []).find(e => e.id === appId)
      return app
    })
    if (app && fromWidget && fromWidget.apps && targetWidget && targetWidget.apps) {
      if (fromWidget.id === targetWidget.id) return
      commit('updateWidget', {
        ...targetWidget,
        ...{
          apps: [
            ...targetWidget.apps,
            app
          ]
        }
      })
      commit('updateWidget', {
        ...fromWidget,
        ...{
          apps: fromWidget.apps.filter(e => e.id !== appId)
        }
      })
      // dispatch('syncAppWidget');
      dispatch('storeSave', null, { root: true })
    }
  },

  async moveOutAppFromWidget ({
    commit,
    state,
    dispatch
  }, {
    widgetId,
    appId
  }: { widgetId: string, appId: string }) {
    let widget = state.widgets.find(e => e.id === widgetId) ||
      state.widgets.find(e => (e.apps || []).find(e => e.id === appId))
    const app = state.apps.find((e: AppWidgetData) => e.id === appId)
    widget = _.cloneDeep(widget)
    if (widget && widget.apps && app) {
      widget.apps = widget.apps.filter(e => e.id !== appId)
      commit('updateWidget', widget)
      dispatch('syncAppWidget')
    } else {
      throw Error('Action moveOutAppFromWidget Fail.')
    }
  },

  incAppClickCount ({
    state,
    commit,
    dispatch
  }, payload) {
    const app = state.apps.find(e => e.id === payload.id)
    if (app) {
      commit('updateApp', {
        ...app,
        clickCount: app.clickCount + 1
      })
      dispatch('storeSave', null, { root: true })
    }
  }
}

export default actions
